package velox.jcr.mapper;

import java.lang.reflect.Method;

import javax.jcr.RepositoryException;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springmodules.jcr.SessionFactoryUtils;



public class LazyBeanFactory {
	final static Logger logger = LoggerFactory.getLogger(LazyBeanFactory.class);
	
	@SuppressWarnings("unchecked")
	public static <T> T create(final String uuid, final Loader<String> loader, final Class<? extends T> type) {
		return (T) Enhancer.create(type, new Class[] { LazyBean.class }, new MethodInterceptor() {
			private Object loadedObject = null;
			
			public Object intercept(Object object, Method method, Object[] args,
					MethodProxy methodProxy) throws Throwable {
				if (method.getName().equals("isLoaded")) {
					return loadedObject != null;
				} else {
					if (loadedObject == null) {
						loadedObject = loadObject();
					}
					return methodProxy.invoke(loadedObject, args);
				}
			}
			
			public Object loadObject() {
				try {
					MapperManager manager = UnitOfWorkHolder.get().getMapperManager();
					logger.debug("Loading lazy bean reference to {} from loader {}", type, loader);
					
					return manager.get(new NodeRef(loader.load(uuid)), type);
				} catch (RepositoryException e) {
					throw SessionFactoryUtils.translateException(e);
				}
			}
		});
	}
	
	public interface LazyBean {
		public boolean isLoaded();
	}
}
